#include "StdAfx.h"
#include "encoding.h"


encoding::encoding(void)
{
}

encoding::~encoding(void)
{
}

//////////////////////////////////////////////////////////////////////////////
//Returns the maximum of two integers
////////////////////////////////////////////////////////////////////////////////

int encoding::Max(int a, int b)
{
	return ((a > b) ? a : b);
}



////////////////////////////////////////////////////////////////////////////
//VectorsCompare:
//Returns 0 if sFirst and sSecond are equal (in all fields)
//If they are not equal return value is 1
///////////////////////////////////////////////////////////////////////////////

int encoding::VectorsCompare(PSVECTOR sFirst, PSVECTOR sSecond)
{
	if ((sFirst->iCycles == sSecond->iCycles) &&
		(sFirst->iValue == sSecond->iValue))
		return 0;
	//Logical else
	return 1;
}





///////////////////////////////////////////////////////////////////////////////
//IdentifyChange
//Returns SIGNAL_ID if there is short vector encoding is relevant
//(only 1 different bit between iFirst and iSecond and it's index is SIGNAL_ID).
//Returns 100 if long vector encoding is relevant
//(more than 1 different bit)
////////////////////////////////////////////////////////////////////////////////

int encoding::IdentifyChange(int iFirst, int iSecond, int iWithStatus)
{
	int iXor;
	int iFound = -1;
	int i=0;
	
	//Check if there is only one different bit	
	iXor = iFirst ^ iSecond;
	while (i < VECTOR_LENGTH)
	{	
		if (iXor % 2 == 1)
		{
			if (iFound == -1)
			{
				iFound = i;//could be VECTOR_LENGTH-i, depends on Big/Little Endian
			}
			//1 different bit was already found - there is more than a single change
			else
			{
				if (iWithStatus)
				{
					return 100;
				}
			}
		}
		iXor = iXor / 2;
		i++;
	}
	//There was no change in vector - ILLEGAL
	if (iFound == -1)
	{
		return -1;
	}
	//There was one change found, in bit index iFound
	return iFound; 
}


////////////////////////////////////////////////////////////////////////////////////
//ShortVector:
//Encoding a vector in the short vector mode. The changed bit is in index iSignalId
//Puts the encoded 32 bit code word into CodeWord.
//Returns 0 if the vector was fully encoded, 1 if there is need in further encoding,
//(When iCycles is too big for two Short Repeat encoding),
//100 if it is possible to encode another ShortVector in same code vector
///////////////////////////////////////////////////////////////////////////////////// 

int encoding::ShortVector(const int iCycles, const int iSignalId,  unsigned int* CodeWord, int iNoUpper)
{
	//Upper 16 bit of the code word
	int iUpper; 
	//Lower 16 bit of the code word
	int iLower;
	//Indicates if further encoding is needed (1 is yes 0 if no)
	int iStatus;

	//If the vector repeats less than SHORT_REPEAT_COUNT times,
	//Will return 100=UPPER_TAKEN (possible to encode another vector)		
	if (iCycles <= SHORT_REPEAT_COUNT )
	{	
		//iUpper taken by previous vector
		if (iNoUpper == 1)
		{
			iLower = ((iSignalId & 0x1F) << 10) + (iCycles & 0x3FF);
			if (CodeWord != NULL)
			{
				*CodeWord += iLower;
			}
			iStatus = DONE;
		}
		//iLower will be free for next vector
		else
		{
			iUpper = ((iSignalId & 0x1F) << 10) + (iCycles & 0x3FF);
			if (CodeWord != NULL)
			{	
				*CodeWord = iUpper << 16;
			}
			iStatus = UPPER_TAKEN;
		}
	}
	else 
	{
		//Need Long Vector
		if (iCycles > 2 * SHORT_REPEAT_COUNT)	
		{
 			
			return NEED_LONG_VECTOR;
		}


		//Use lower 16 bit to indicate "Short repeat" 	
		else
		{
			//Impossible to encode in 16 bit
			if (iNoUpper == 1) 
			{
				return FAIL;
			}
			//Logical else
			iUpper = ((iSignalId & 0x1F) << 10) + (SHORT_REPEAT_COUNT & 0x3FF);
			iLower =	(((VECTOR_LENGTH+1) & 0x1F) <<10) + 
						((iCycles - SHORT_REPEAT_COUNT) & 0x3FF);
			
		
			iStatus = DONE;
		}
		if (CodeWord != NULL)
		{
			*CodeWord = (iUpper << 16) + iLower;
		}
	}

	return iStatus;
}




//////////////////////////////////////////////////////////////////////////////
//LongVector:
//Creates a LongVector code word - this vector repeats at least once
//Cannot fail, but has return value to be matching with ShortVector and LongRepeat
//Returns 50 to symbolize that further encoding is needed (always need LongRepeat
//after LongVector and cycles there are dec by 1 cause LongVector is already repeated
//once)
////////////////////////////////////////////////////////////////////////////// 


int encoding::LongVector(const int iValue, const int iCycles, unsigned int* CodeWord)
{
	if (CodeWord != NULL)
	{
		*CodeWord = iValue + (2 << 30);
	}
	//if only 1 cycle no LongRepeat needed
	if (iCycles == 1)
	{
		return DONE;
	}
	//logical else
	return USE_LONG_REPEAT;
}




//////////////////////////////////////////////////////////////////////////////
//LongRepeat:
//Creates a LongRepeat code word.
//Notice: iCycles - 1 is encoded, because LongVector represents a sole vector,
//and LongRepeat represents the number of repeats after that. 
//iStatus > 0 means iCycles of the vector > LONG_REPEAT_COUNT, and iStatus
//times the LONG_REPEAT_COUNT of the iCycles were already encoded.
//Hence there are sVector->iCycles - LONG_REPEAT_COUNT * iStatus
//left to encode. If 16 bit of the LONG_REPEAT_COUNT are not 
//enough to it, LONG_REPEAT_COUNT cycles are encoded, iStatus is incremented
//Otherwise (done encoding this Vector) iStatus is 0
//Either way the updated iStatus is the return value.
///////////////////////////////////////////////////////////////////////////////

int encoding::LongRepeat(const int iCycles, unsigned int* CodeWord, int iStatus)
{
	int iCyclesLeft;
	
	//If there was Long Vector before this then need to dec by 1 
	if (iStatus == USE_LONG_REPEAT)
	{
		iCyclesLeft = iCycles - 1;
	}
	
	//If this is Long Repeat after Short Vector or another LongRepeat, 
	//no need to decrease 1 
	else 
	{
		iCyclesLeft = iCycles - LONG_REPEAT_COUNT * (iStatus - 1);
	}
	if (iCyclesLeft <= LONG_REPEAT_COUNT)
	{
		if (CodeWord != NULL)
		{
			*CodeWord = iCyclesLeft + (3 << 30);
		}
		iStatus = DONE;
	}
	else
	{
		if (CodeWord != NULL)
		{
			*CodeWord = LONG_REPEAT_COUNT + (3 << 30);
		}
		iStatus ++;
	}
	return iStatus;
}




//////////////////////////////////////////////////////////////////////////////
//Encode:
//Encodes Vectors which are stored in array from sFirstVector to sLastVector.
//The encoded words are stored in iCodeArray.
//iIsDependant == DEPENDANT means we encode sFirstVector using the 
//Vector before it in Vector array(sFirstVector - 1).
//iIsDependant == INDEPENDANT means sFirstVector is encoded independantly - 
//as Long Vector + Long Repeat. 
//iLongVector indicates number of Long Vectors used in the encoding
//Return value is number of words in iCodeArray. 
//(iCodeArray + Return value is the next free element in iCodeArray)
//Assuming SVECTOR array (NOT array of pointers to Vectors)
//If iCodeArray is NULL thw fuction counts number of words it would have 
//taken to encode (without actually encoding)
//////////////////////////////////////////////////////////////////////////////////

int encoding::Encode(const PSVECTOR sFirstVector, const PSVECTOR sLastVector, unsigned int* iCodeArray, int iIsDependant, int* iLongVectors)
{
	int i = 0; //Vector index
	int j = 0; //Index in iCodeArray
	int iLower = 0;
	int iStatus;
	int iSignalId;
	int iNumberOfVectors;

	iNumberOfVectors = sLastVector - sFirstVector + 1;
	
	
	if (iIsDependant == INDEPENDANT)
	{
		if ((sFirstVector)->iCycles == 0)
		{
			i ++;
		}
		iStatus  = (iCodeArray != NULL) ?
			(LongVector((sFirstVector + i)->iValue, (sFirstVector + i)->iCycles, iCodeArray)) :
			(LongVector((sFirstVector + i)->iValue, (sFirstVector + i)->iCycles, NULL));
		//Statistics
		*iLongVectors +=1;

		j++;
		while (iStatus)
				{
					iStatus = (iCodeArray != NULL) ? 
						(LongRepeat((sFirstVector + i)->iCycles, (iCodeArray + j), iStatus)) :
						(LongRepeat((sFirstVector + i)->iCycles, NULL , iStatus));
					j++; //Go to next Code Word in iCodeArray
				}
		i ++;
	}
	while (i < iNumberOfVectors)
	{
		//Irrelevant vector
		if ((sFirstVector)[i].iCycles == 0)
		{
			i ++;
			continue;
		}

		//Previous vector is irrelevant and we should not compare with it
		if ((sFirstVector)[i - 1].iCycles == 0)
		{
			iSignalId = IdentifyChange((sFirstVector + i - 2)->iValue, (sFirstVector + i)->iValue,ON);
		}
		//Previous vector is relevant
		else
		{
			iSignalId = IdentifyChange((sFirstVector + i - 1)->iValue, (sFirstVector + i)->iValue,ON);
		}
		//identical value - ILLEGAL. The vector (and it's cycles ) is lost
		if (iSignalId == -1)
		{
			i ++;
			continue;
		}

		if (iSignalId <= 30) 
		{
			iStatus = (iCodeArray != NULL) ?
				(ShortVector((sFirstVector + i)->iCycles, iSignalId, (iCodeArray + j), iLower)) :
				(ShortVector((sFirstVector + i)->iCycles, iSignalId, NULL, iLower));
			
		}
		//2 changes, or previous vector has more than 2*SHORT_REPEAT cycles) 
		if ( (iSignalId > 30) || (iStatus == NEED_LONG_VECTOR) ) 
		{
			//Previous vector was short, left room in lower 16 bit of code word,
			//but this vector is LongVector so we need to put Skip in lower 16 bit
			//and go to next code word
			if (iLower == 1)
			{
				if (iCodeArray != NULL)
				{
					*(iCodeArray + j) += SKIP;
				}
				j ++;
			}

			iStatus = (iCodeArray != NULL) ?
				(LongVector((sFirstVector + i)->iValue, 
						(sFirstVector + i)->iCycles, 
						(iCodeArray + j)) ) :
				(LongVector((sFirstVector + i)->iValue, 
						(sFirstVector + i)->iCycles, 
						NULL) );

			//Statistics:
			*iLongVectors +=1;
		}
		
		// ShortVector failed to encode vector in lower part
		if (iStatus == FAIL)
		{
			//Previous vector was short, left room in lower 16 bit of code word,
			//but this vector's cycles dont fit in  one SHORT_REPEAT so we need to put 
			//Skip in lower 16 bit and go to next code word(Status == FAIL) or
			//use LongVector (Status == NEED_LONG_VECTOR)
	
			if (iLower == 1)
			{
				if (iCodeArray != NULL)
				{
					*(iCodeArray + j) += SKIP;
				}
			}
			//Need to encode same vector in next code word				
			j ++;
			iLower = 0;
			continue;
		}
		//Done encoding in lower part of 32 bit, now should encode in upper 
		if (iLower == 1)
		{
			iLower = 0;
		}

		//ShortVector returned that its possible to encode another short vector 
		//in the same code word
		if (iStatus == UPPER_TAKEN)
		{	
			iLower = 1;
			iStatus = DONE;
			if (i == iNumberOfVectors - 1)
			//end of this Encode - should align to 32 bit - put Skip in lower  
			{
				if (iCodeArray != NULL)
				{
					*(iCodeArray + j) += SKIP;
				}
			}
			else
			{
				//Want to encode in same code word, j ++ will follow
				j --;
			}
		}


		j++;
		while (iStatus)
		{
			iStatus = (iCodeArray != NULL) ? 
				(LongRepeat((sFirstVector + i)->iCycles, (iCodeArray + j), iStatus) ):
				(LongRepeat((sFirstVector + i)->iCycles, NULL, iStatus) );
			j++; //Go to next Code Word in iCodeArray
		}
		i++; //Go to next Vector 
	}
 	return j;
			
}


//////////////////////////////////////////////////////////////////////
//Encoding StartLoop marker
////////////////////////////////////////////////////////////////////

int encoding::StartLoop(void)
{
	return ( (3 << 30) + (2 << 16) );
}


//////////////////////////////////////////////////////////////////////
//Encoding EndLoop marker
////////////////////////////////////////////////////////////////////

int encoding::EndLoop(int iLoopCount)
{
	return ( (3 << 30) + (1 << 16) + iLoopCount );
}

//////////////////////////////////////////////////////////////////////////////////
//EncodeBlock:
//Given a Block Array, with marked LOOP and FLAT areas, encoding the Vectors
//into iCodeArray. Using Encode function, adding StartLoop, EndLoop markers.
//iLongVector indicates number of Long Vectors used in the encoding
//Return Value : Number of words in iCodeArray
///////////////////////////////////////////////////////////////////////////////// 

int encoding::EncodeBlock(PSBLOCK sBlockArray, int iNumberOfBlocks,  unsigned int* iCodeArray, int* iLongVectors, int* iMaxDwordsInLoop, int* iMarkers)
{
	int iBlockIndex = 0;
	int iCodeIndex = 0;
	int iCodeWords = 0;
	int iBeforeLoop = 0;
	int tmp;
							
	while (iBlockIndex < iNumberOfBlocks)
	{
		//Encode first vector
		if (iBlockIndex == 0)
		{
			iCodeWords = Encode(	(sBlockArray[iBlockIndex].sFirst),
							(sBlockArray[iBlockIndex].sFirst),
							iCodeArray + iCodeIndex,
							INDEPENDANT,
							iLongVectors);
		}
		else
		{
			iCodeWords = Encode(	(sBlockArray[iBlockIndex].sFirst),
							(sBlockArray[iBlockIndex].sFirst),
							iCodeArray + iCodeIndex,
							DEPENDANT,
							iLongVectors);
		}
		iCodeIndex += iCodeWords;
		//Start Loop marker if needed
		if (sBlockArray[iBlockIndex].LoopOrFlat == LOOP)
		{
			//Need to insert StartLoop after first code word
			if (iCodeWords == 2)
			{
				tmp = iCodeArray[iCodeIndex - 1];
				iCodeArray[iCodeIndex - 1] = StartLoop();
				iCodeArray[iCodeIndex] = tmp;
			}
			//iCodeWords == 1
			else
			{
				iCodeArray[iCodeIndex] = StartLoop();
			}
			iCodeIndex ++;

			iBeforeLoop = iCodeWords;
			*iMarkers += 1;
		}
		
		//Loop (or Flat) body (except first vector)
		iCodeWords = Encode(	(sBlockArray[iBlockIndex].sFirst + 1),
							(sBlockArray[iBlockIndex].sLast),
							iCodeArray + iCodeIndex,
							DEPENDANT,
							iLongVectors);	

		iCodeIndex += iCodeWords;
		
		//End Loop marker
		if (sBlockArray[iBlockIndex].LoopOrFlat == LOOP)
		{
			//PATCH - can't have SKIP before EndLoop, so we put Long Vector instead
			if ( (iCodeArray[iCodeIndex - 1] & 0xF) == SKIP )
			{
				iCodeWords = Encode((sBlockArray[iBlockIndex].sLast),
							(sBlockArray[iBlockIndex].sLast),
							iCodeArray + iCodeIndex - 1,
							INDEPENDANT,
							iLongVectors);
				iCodeArray += (iCodeWords - 1);
			}
							
			//Note the -1!!
			iCodeArray[iCodeIndex] = EndLoop(sBlockArray[iBlockIndex].sLoopData->iLoopCount - 1);
			iCodeIndex ++;

			*iMaxDwordsInLoop = Max(*iMaxDwordsInLoop, iCodeWords + iBeforeLoop);
			*iMarkers +=1;
		}
		iBlockIndex++;
	}
	//Number of words in the compressed output
	return iCodeIndex;

}
